package cn.org.processor.guestbook.api.service.impl;

import cn.org.processor.guestbook.api.mapper.*;
import cn.org.processor.guestbook.api.model.request.ListMessageByTopicRequest;
import cn.org.processor.guestbook.api.model.request.MessageCreateRequest;
import cn.org.processor.guestbook.api.model.request.MessageDiscardRequest;
import cn.org.processor.guestbook.api.model.request.MessageReplyRequest;
import cn.org.processor.guestbook.api.model.response.MessageDetailResponse;
import cn.org.processor.guestbook.api.service.MessageService;
import cn.org.processor.guestbook.api.util.ContextHolderUtil;
import entity.*;
import io.Page;
import io.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import util.PageUtil;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MessageServiceImpl implements MessageService {
    private final TopicMapper topicMapper;
    private final MessageMapper messageMapper;
    private final ReplyMapper replyMapper;
    private final UserMapper userMapper;
    private final UserProfileMapper userProfileMapper;
    private final WalletMapper walletMapper;

    public MessageServiceImpl(TopicMapper topicMapper, MessageMapper messageMapper, ReplyMapper replyMapper,
                              UserMapper userMapper, UserProfileMapper userProfileMapper, WalletMapper walletMapper) {
        this.topicMapper = topicMapper;
        this.messageMapper = messageMapper;
        this.replyMapper = replyMapper;
        this.userMapper = userMapper;
        this.userProfileMapper = userProfileMapper;
        this.walletMapper = walletMapper;
    }

    @Override
    @Transactional
    public Response create(MessageCreateRequest request) {
        if (request.getTopicId() != null) {
            Topic topic = topicMapper.findById(request.getTopicId());
            if (topic == null) {
                return Response.builder().ret(Response.Ret.FAILURE).msg("话题不存在").build();
            }

            if (topic.getStatus() != Topic.Status.OPEN) {
                return Response.builder().ret(Response.Ret.FAILURE).msg("话题已被关闭").build();
            }

            // 消息如果是在话题中，则必须是公开的
            request.setType(Message.Type.OPEN);
        }

        // 消息类型为私密或公开时，接收者为空
        if (Objects.equals(request.getType(), Message.Type.PRIVATE) ||
                Objects.equals(request.getType(), Message.Type.OPEN)) {
            request.setReceiveUserId(null);
        }

        User user = (User) ContextHolderUtil.getCurrentUser();
        if (request.getReceiveUserId() != null) {
            // 判断余额是否足够
            Wallet wallet = walletMapper.findById(user.getId());
            UserProfile receiveProfile = userProfileMapper.findById(request.getReceiveUserId());
            // 如果接收者设定了咨询单价，则需要进行支付
            if (receiveProfile.getConsultPrice() != null) {
                if (wallet.getCoin() < receiveProfile.getConsultPrice()) {
                    return Response.builder().ret(Response.Ret.FAILURE).msg("您的金币不足，请先充值").build();
                }

                // 扣除金币
                log.info("Deduct user {} coins: {} -> {}, total: {}", user.getId(), wallet.getCoin(),
                        wallet.getCoin() - receiveProfile.getConsultPrice(), receiveProfile.getConsultPrice());

                wallet.setCoin(wallet.getCoin() - receiveProfile.getConsultPrice());
                int result = walletMapper.update(wallet);
                if (result == 0) {
                    log.error("Failed to update wallet for sender, wallet: {}", wallet);

                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Response.builder().ret(Response.Ret.FAILURE).msg("服务器出错了").build();
                }

                // 接收者增加金币
                Wallet receiveWallet = walletMapper.findById(request.getReceiveUserId());
                log.info("Add user {} coins: {} -> {}, total: {}", request.getReceiveUserId(), receiveWallet.getCoin(),
                        receiveWallet.getCoin() + receiveProfile.getConsultPrice(), receiveProfile.getConsultPrice());

                receiveWallet.setCoin(receiveWallet.getCoin() + receiveProfile.getConsultPrice());
                result = walletMapper.update(receiveWallet);
                if (result == 0) {
                    log.error("Failed to update wallet for recipient, wallet: {}", receiveWallet);

                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Response.builder().ret(Response.Ret.FAILURE).msg("服务器出错了").build();
                }
            }
        }

        Message message = new Message();
        message.setUserId(user.getId());
        message.setTopicId(request.getTopicId());
        message.setReceiveUserId(request.getReceiveUserId());
        message.setType(request.getType());
        message.setContent(request.getContent());
        message.setDate(new Date());
        message.setReplyStatus(Message.ReplyStatus.NO_REPLY);
        message.setStatus(Message.Status.VISIBLE);

        if (messageMapper.create(message) > 0) {
            return Response.builder().ret(Response.Ret.SUCCESS).msg("留言成功").data(message.getId()).build();
        }

        log.error("Failed to create message, message: {}", message);
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        return Response.builder().ret(Response.Ret.FAILURE).msg("留言失败").build();
    }

    @Override
    public Response listByCurrentUser(Page page) {
        User user = (User) ContextHolderUtil.getCurrentUser();
        List<Message> messages = messageMapper.listByUserId(user.getId(),
                PageUtil.getStartRows(page.getPage(), page.getOffset()), page.getOffset());

        return Response.builder().ret(Response.Ret.SUCCESS).msg("获取成功").data(messages).build();
    }

    @Override
    public Response listByReceive(Page page) {
        User user = (User) ContextHolderUtil.getCurrentUser();
        List<Message> messages = messageMapper.listByReceiveUserId(user.getId(),
                PageUtil.getStartRows(page.getPage(), page.getOffset()), page.getOffset());

        return Response.builder().ret(Response.Ret.SUCCESS).msg("获取成功").data(messages).build();
    }

    @Override
    public Response pick() {
        User user = (User) ContextHolderUtil.getCurrentUser();
        List<Message> messages = messageMapper.findByPickUserIdAndNoReply(user.getId());
        if (messages.size() > 0) {
            return Response.builder()
                    .ret(Response.Ret.FAILURE)
                    .msg("当前有未处理的留言")
                    .data(messages.stream().map(Message::getId))
                    .build();
        }

        Message message = messageMapper.findOneInWaitPick(user.getId());
        if (message == null) {
            return Response.builder().ret(Response.Ret.FAILURE).msg("留言被人捞光了，晚点再来吧").build();
        }

        message.setPickUserId(user.getId());
        if (messageMapper.update(message) > 0) {
            return Response.builder().ret(Response.Ret.SUCCESS).msg("捞到了一条留言").data(message.getId()).build();
        }

        log.error("Failed to pick message, message: {}", message);
        return Response.builder().ret(Response.Ret.FAILURE).msg("打捞失败").build();
    }

    @Override
    public Response discard(MessageDiscardRequest request) {
        Message message = messageMapper.findById(request.getId());
        if (message == null) {
            return Response.builder().ret(Response.Ret.FAILURE).msg("留言不存在").build();
        }

        User user = (User) ContextHolderUtil.getCurrentUser();
        if (!Objects.equals(message.getPickUserId(), user.getId())) {
            return Response.builder().ret(Response.Ret.FAILURE).msg("这不是您捞到的留言").build();
        }

        if (message.getReplyStatus() == Message.ReplyStatus.HAS_REPLY) {
            return Response.builder().ret(Response.Ret.FAILURE).msg("留言已回复过，不能丢回大海了").build();
        }

        if(messageMapper.updateForDiscard(message.getId()) > 0) {
            return Response.builder().ret(Response.Ret.SUCCESS).msg("留言已丢回大海").build();
        }

        log.error("Failed to discard message, message: {}", message);
        return Response.builder().ret(Response.Ret.FAILURE).msg("服务器出错了").build();
    }

    @Override
    @Transactional
    public Response reply(MessageReplyRequest request) {
        Message message = messageMapper.findById(request.getMessageId());
        if (message == null) {
            return Response.builder().ret(Response.Ret.FAILURE).msg("留言不存在").build();
        }

        // 除了话题下的留言除外，只有发这条留言和收到这条留言的用户可以回复，其他人不能回复
        User user = (User) ContextHolderUtil.getCurrentUser();
        if (message.getTopicId() == null &&
                (!Objects.equals(message.getPickUserId(), user.getId()) &&
                        !Objects.equals(message.getReceiveUserId(), user.getId()) &&
                        !Objects.equals(message.getUserId(), user.getId()))) {
            return Response.builder().ret(Response.Ret.FAILURE).msg("这条留言不属于你，无法回复").build();
        }

        // 插入回复
        Reply reply = new Reply();
        reply.setMessageId(message.getId());
        reply.setUserId(user.getId());
        reply.setContent(request.getContent());
        reply.setDate(new Date());
        reply.setStatus(Reply.Status.NORMAL);
        if (replyMapper.create(reply) > 0) {
            // 更新回复状态
            message.setReplyStatus(Message.ReplyStatus.HAS_REPLY);
            if (messageMapper.update(message) > 0) {
                return Response.builder().ret(Response.Ret.SUCCESS).msg("回复成功").build();
            }

            log.error("Failed to update message, message: {}", message);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Response.builder().ret(Response.Ret.FAILURE).msg("服务器出错了").build();
        }

        log.error("Failed to create reply, reply: {}", reply);
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        return Response.builder().ret(Response.Ret.FAILURE).msg("服务器出错了").build();
    }

    @Override
    public Response detail(Integer id) {
        Message message = messageMapper.findById(id);
        if (message == null) {
            return Response.builder().ret(Response.Ret.FAILURE).msg("留言不存在").build();
        }

        User user = (User) ContextHolderUtil.getCurrentUser();
        // 非话题下的留言
        if (message.getTopicId() == null) {
            // 仅发出这条留言和收到这条留言的用户可以查看
            if (!Objects.equals(message.getPickUserId(), user.getId()) &&
                    !Objects.equals(message.getReceiveUserId(), user.getId()) &&
                    !Objects.equals(message.getUserId(), user.getId())) {
                return Response.builder().ret(Response.Ret.FAILURE).msg("这条留言不属于你，无法查看").build();
            }

            // 适用于非指定用户收取的留言被打捞到后被发出者设为私密的情况
            if (message.getType() == Message.Type.PRIVATE &&
                    message.getReceiveUserId() == null && !Objects.equals(message.getUserId(), user.getId())) {
                return Response.builder().ret(Response.Ret.FAILURE).msg("留言已被设为私密，无法查看").build();
            }
        }

        // 获取回复列表以及回复的用户信息
        List<Reply> replies = replyMapper.findByMessageId(id);
        List<MessageDetailResponse.UserData> userDataList = null;
        if (replies.size() > 0) {
            List<Integer> userIds = replies.stream().map(Reply::getUserId).distinct().collect(Collectors.toList());
            List<User> users = userMapper.findByIds(userIds);
            List<UserProfile> userProfiles = userProfileMapper.findByUserIds(userIds);

            // 将用户信息和回复信息组合
            userDataList = users.stream().map(item -> {
                MessageDetailResponse.UserData userData = new MessageDetailResponse.UserData();
                userData.setId(item.getId());
                userData.setUsername(item.getUsername());
                userData.setIntro(userProfiles.stream()
                        .filter(profile -> Objects.equals(profile.getId(), item.getId()))
                        .findFirst()
                        .map(UserProfile::getIntro)
                        .orElse(null));

                return userData;
            }).collect(Collectors.toList());
        }

        MessageDetailResponse response = new MessageDetailResponse();
        response.setMessage(message);
        response.setReplyList(replies);
        response.setUserData(userDataList);

        return Response.builder().ret(Response.Ret.SUCCESS).msg("获取成功").data(response).build();
    }

    @Override
    public Response listByPick(Page page) {
        User user = (User) ContextHolderUtil.getCurrentUser();
        List<Message> messages = messageMapper.listByPick(user.getId(),
                PageUtil.getStartRows(page.getPage(), page.getOffset()), page.getOffset());

        return Response.builder().ret(Response.Ret.SUCCESS).msg("获取成功").data(messages).build();
    }

    @Override
    public Response listByTopic(ListMessageByTopicRequest request) {
        Topic topic = topicMapper.findById(request.getTopicId());
        if (topic == null) {
            return Response.builder().ret(Response.Ret.FAILURE).msg("话题不存在").build();
        }

        Page page = request.getPage();
        int start = PageUtil.getStartRows(page.getPage(), page.getOffset());
        List<Message> messages = messageMapper.listByTopic(request.getTopicId(), start, page.getOffset());

        return Response.builder().ret(Response.Ret.SUCCESS).msg("获取成功").data(messages).build();
    }
}
